#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <unordered_map>

#include "Sock.hpp"
#include "log.hpp"
#include "Epoll.hpp"

// sock必须要有自己独立的接收缓冲区和发送缓冲区

class TcpServer;
class Connection;

using func_t = std::function<void(Connection*)>; // 此处的using意为typedef

class Connection
{
public:
    Connection(int sock = -1)
        : _sock(sock)
        , _tsvr(nullptr)
    {}
    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    ~Connection()
    {}
public:
    int _sock;         // 负责进行IO的文件描述符

    func_t _recv_cb;   // 读事件回调函数 
    func_t _send_cb;   // 写事件回调函数
    func_t _except_cb; // 异常事件回调函数

    std::string _inbuffer; // 接收缓冲区
    std::string _outbuffer; // 发送缓冲区

    TcpServer* _tsvr; // 回值指针，指向原来的TcpServer
};

class TcpServer
{
public:
    TcpServer(int port = 8080)
        : _port(port)
    {
        // 创建套接字
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);

        // 创建epoll模型
        _poll.CreateEpoll();

        // 我们要将所有的sock都添加到epoll模型中，所以要管理所有的sock，使用unordered_map
        AddConnection(_listensock, Accepter, nullptr, nullptr);
    }

    // 将任意sock添加到TcpServer
    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        // 需要循环读取，所以设置sock为非阻塞
        Sock::SetNonBlock(sock);
        // 实例化sock对象
        Connection* conn = new Connection(_listensock);
        conn->SetCallBack(recv_cb, send_cb, except_cb);
        conn->_tsvr = this;

        // 将sock添加到epoll
        _poll.AddSockToEpoll(sock, EPOLLIN | EPOLLET); // 多路转接的服务器，一般只打开读事件的关心，写事件按需打开

        // 将sock添加到map中
        _connections.insert(std::make_pair(sock, conn));
    }

    static void Accepter(Connection* conn)
    {
        std::string clientip;
        uint16_t clientport;
        int sock = Sock::Accept(conn->_sock, &clientip, &clientport);

        conn->_tsvr->AddConnection(sock, conn->_tsvr->Recver, nullptr, nullptr);
    }

    static void Recver(Connection* conn)
    {
        char buffer[1024];
        int n = 0;
        while (recv(conn->_sock, buffer, sizeof(buffer) - 1, 0) != EAGAIN)
        {
            conn->_inbuffer += buffer;
        }
    }

    void Start()
    {

    }

    ~TcpServer()
    {
        if (_listensock > 0) close(_listensock);
    }

private:
    int _listensock;
    int _port;
    Epoll _poll;
    std::unordered_map<int, Connection*> _connections; // sock : Connection*
};